#include "lcd_cortex.h"
#include "sys_config.h"
#include <lcd.h>
#include <board.h>


long dev_lcd;
extern unsigned short *tftptr;
extern unsigned int TypPCB;

static CLCDC_CFG_T lcdcfg;

const LCD_PARAM_T truly_tft_g240320ltsw_118w_e_portrait =
{
		5,      // Horizontal back porch  -> bylo 5
		5,      // Horizontal front porch -> bylo 5
		160,     // HSYNC pulse width 	-> bylo 160
		640,     // Pixels per line
		6,       // Vertical back porch -> bylo 6
		6,       // Vertical front porch -> bylo 6
		40,      // VSYNC pulse width -> bylo 40
		480,     // Lines per panel
		0,       // Invert output enable
		1,       // Do not invert panel clock !!!!!!!!!!!!! bylo 1
		1,       // Invert HSYNC
		1,       // Invert VSYNC
		1,       // AC bias frequency (not used)
		16,      // Bits per pixel
		4800000, // Optimal clock rate (Hz) 4800000
		TFT,     // LCD panel type
		0,       // Single panel display
};

const LCD_PARAM_T nl6448bc2018d =
{
		48,      // Horizontal back porch 48
		16,      // Horizontal front porch
		96,     // HSYNC pulse width 96
		640,     // Pixels per line
		31,       // Vertical back porch
		12,       // Vertical front porch
		2,      // VSYNC pulse width
		480,     // Lines per panel
		0,       // Invert output enable
		0,       // Do not invert panel clock
		1,       // Invert HSYNC
		1,       // Invert VSYNC
		1,       // AC bias frequency (not used)
		16,      // Bits per pixel
		4800000, // Optimal clock rate (Hz)
		TFT,     // LCD panel type
		0,       // Single panel display
};

//800/480 -Glyn
const LCD_PARAM_T get0700g0dm6 =
{
		88,      // Horizontal back porch 88
		40,      // Horizontal front porch 40
		128,     // HSYNC pulse width
		800,     // Pixels per line bylo 800
		33,       // Vertical back porch 33
		10,       // Vertical front porch 10
		2,      // VSYNC pulse width
		480,     // Lines per panel
		0,       // Invert output enable
		0,       // Do not invert panel clock
		1,       // Invert HSYNC
		1,       // Invert VSYNC
		1,       // AC bias frequency (not used)
		16,      // Bits per pixel
		4800000, // Optimal clock rate (Hz)
		TFT,     // LCD panel type
		0,       // Single panel display
};


//800/480 -Glyn
const LCD_PARAM_T get0700g0dm6_invclk =
{
		88,      // Horizontal back porch 88
		40,      // Horizontal front porch 40
		128,     // HSYNC pulse width
		800,     // Pixels per line bylo 800
		33,       // Vertical back porch 33
		10,       // Vertical front porch 10
		2,      // VSYNC pulse width
		480,     // Lines per panel
		0,       // Invert output enable
		1,       // Do not invert panel clock
		1,       // Invert HSYNC
		1,       // Invert VSYNC
		1,       // AC bias frequency (not used)
		16,      // Bits per pixel
		4800000, // Optimal clock rate (Hz)
		TFT,     // LCD panel type
		0,       // Single panel display
};






// Toshiba LTA057A347F display IRD 2.0 2478 Board
const LCD_PARAM_T LCD_LTA057A347F_params16bit =
{
		30,      // Horizontal back porch
		10,      // Horizontal front porch
		96,      // HSYNC pulse width
		320,     // Pixels per line
		8,       // Vertical back porch
		2,       // Vertical front porch
		15,      // VSYNC pulse width
		240,     // Lines per panel
		0,       // Invert output enable
		0,       // 0,Do not invert panel clock
		0,       // 0,Invert HSYNC
		0,       // 0,Invert VSYNC
		0,       // 0,AC bias frequency (not used)
		16,      // Bits per pixel
		4800000, // Optimal clock rate (Hz)
		TFT,     // LCD panel type
		0,       // Single panel display
};


void lcd_configure_gpio(void)
{
	//	PINSEL3 = (PINSEL3 & 0xF00000FF) | 0x05555500;
	//	PINSEL4 = (PINSEL4 & 0xF0C00000) | 0x050FFFFC; //1010000 1111 1111 1111 1111 1100
	//	PINSEL9 = (PINSEL9 & 0xF0FFFFFF) | 0x0A000000;

	//HSYNC
	LPC_IOCON->P2_5 = (LPC_IOCON->P2_5&(~0xFFF)) | 0x07;
	//VSYNC
	LPC_IOCON->P2_3 = (LPC_IOCON->P2_3&(~0xFFF)) | 0x07;
	//DEN - p2.4
	LPC_IOCON->P2_4 = (LPC_IOCON->P2_4&(~0xFFF)) | 0x07;
	//CLK - p2.2
	LPC_IOCON->P2_2 = (LPC_IOCON->P2_2&(~0xFFF)) | 0x07;

	//LCDVD_2 - p4.28
	LPC_IOCON->P4_28 = (LPC_IOCON->P4_28&(~0xFFF)) | 0x07;
	//LCDVD_3 - p4.29
	LPC_IOCON->P4_29 = (LPC_IOCON->P4_29&(~0xFFF)) | 0x07;
	//LCDVD_4 - p2.6
	LPC_IOCON->P2_6 = (LPC_IOCON->P2_6&(~0xFFF)) | 0x07;
	//LCDVD_5 - p2.7
	LPC_IOCON->P2_7 = (LPC_IOCON->P2_7&(~0xFFF)) | 0x07;
	//LCDVD_6 - p2.8
	LPC_IOCON->P2_8 = (LPC_IOCON->P2_8&(~0xFFF)) | 0x07;
	//LCDVD_7 - p2.9
	LPC_IOCON->P2_9 = (LPC_IOCON->P2_9&(~0xFFF)) | 0x07;

	//LCDVD_10 - p2.7
	LPC_IOCON->P1_20 = (LPC_IOCON->P1_20&(~0xFFF)) | 0x07;
	//LCDVD_11 - p1.21
	LPC_IOCON->P1_21 = (LPC_IOCON->P1_21&(~0xFFF)) | 0x07;
	//LCDVD_12 - p1.22
	LPC_IOCON->P1_22 = (LPC_IOCON->P1_22&(~0xFFF)) | 0x07;
	//LCDVD_13 - p1.23
	LPC_IOCON->P1_23 = (LPC_IOCON->P1_23&(~0xFFF)) | 0x07;
	//LCDVD_14 - p1.24
	LPC_IOCON->P1_24 = (LPC_IOCON->P1_24&(~0xFFF)) | 0x07;
	//LCDVD_15 - p1.25
	LPC_IOCON->P1_25 = (LPC_IOCON->P1_25&(~0xFFF)) | 0x07;


	//LCDVD_18 - p2.12
	LPC_IOCON->P2_12 = (LPC_IOCON->P2_12&(~0xFFF)) | 0x07;
	//LCDVD_19 - p2.13
	LPC_IOCON->P2_13 = (LPC_IOCON->P2_13&(~0xFFF)) | 0x07;
	//LCDVD_20 - p1.26
	LPC_IOCON->P1_26 = (LPC_IOCON->P1_26&(~0xFFF)) | 0x07;
	//LCDVD_21 - p1.27
	LPC_IOCON->P1_27 = (LPC_IOCON->P1_27&(~0xFFF)) | 0x07;
	//LCDVD_22 - p1.28
	LPC_IOCON->P1_28 = (LPC_IOCON->P1_28&(~0xFFF)) | 0x07;
	//LCDVD_23 - p1.29
	LPC_IOCON->P1_29 = (LPC_IOCON->P1_29&(~0xFFF)) | 0x07;
}

#if 0
long lcd_open(void *lcdbase, long arg)
{
  long status = 0;

  if ((lcdcfg.init == 0) && ((CLCDC_REGS_T *) lcdbase == CLCDC))
  {
    //Device is valid and not previously initialized
    lcdcfg.init = 1;

    // Save and return address of peripheral block
    lcdcfg.regptr = (CLCDC_REGS_T *) lcdbase;
    lcdcfg.dptr = (LCD_PARAM_T *) arg;

    // Disable LCD
    lcdcfg.regptr->lcdctrl &= ~CLCDC_LCDCTRL_ENABLE;

    // If the passed argument is not NULL, then it is a pointer
    //   to a LCD panel parameters structure that needs to be configured
    if (arg != 0)
    {
      lcd_initialize(&lcdcfg);
      lcd_configure_gpio();
    }

    /* Return pointer to LCD configuration data structure */
    status = (long) &lcdcfg;
  }
  return status;
}
#endif

int32_t lcd_open(int32_t arg)
{
  int32_t status = 0;

  if (lcdcfg.init == FALSE)
  {
    /* Device is valid and not previously initialized */
    lcdcfg.init = TRUE;

    /* Save and return address of peripheral block */
    lcdcfg.dptr = (LCD_PARAM_T *) arg;

    /* Disable LCD */
    LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_ENABLE;

    /* If the passed argument is not NULL, then it is a pointer
       to a LCD panel parameters structure that needs to be configured */
    if (arg != 0)
    {
      lcd_initialize(&lcdcfg);
      lcd_configure_gpio();
    }

    /* Return pointer to LCD configuration data structure */
    status = (int32_t) &lcdcfg;
  }
  return status;
}

#if 0
unsigned int lcd_initialize(CLCDC_CFG_T *lcdcfgptr)
{
  unsigned int tmp, i;
  long status = 0;
  CLCDC_REGS_T *lcdptr = lcdcfgptr->regptr;
  LCD_PARAM_T *cgdatptr = lcdcfgptr->dptr;

  // Disable the display in case it is on
  lcdptr->lcdctrl &= ~CLCDC_LCDCTRL_ENABLE;

  // Generate the horizontal axis plane control word
  tmp = (CLCDC_LCDTIMING0_PPL(cgdatptr->pixels_per_line) |
         CLCDC_LCDTIMING0_HSW(cgdatptr->h_sync_pulse_width) |
         CLCDC_LCDTIMING0_HFP(cgdatptr->h_front_porch) |
         CLCDC_LCDTIMING0_HBP(cgdatptr->h_back_porch));
  lcdptr->lcdtiming0 = tmp;

  // Generate the vertical axis plane control word
  tmp = (CLCDC_LCDTIMING1_LPP(cgdatptr->lines_per_panel) |
         CLCDC_LCDTIMING1_VSW(cgdatptr->v_sync_pulse_width) |
         CLCDC_LCDTIMING1_VFP(cgdatptr->v_front_porch) |
         CLCDC_LCDTIMING1_VBP(cgdatptr->v_back_porch));
  lcdptr->lcdtiming1 = tmp;

  // Generate the clock and signal polarity control word
  if(cgdatptr->ac_bias_frequency != 0)
  {
    // STN panel has AC bias value
    tmp = CLCDC_LCDTIMING2_ACB(cgdatptr->ac_bias_frequency);
  }
  else
  {
    tmp = 0;
  }

  if (cgdatptr->invert_output_enable != 0)
  {
    tmp |= CLCDC_LCDTIMING2_IOE;
  }

  if (cgdatptr->invert_panel_clock != 0)
  {
    tmp |= CLCDC_LCDTIMING2_IPC;
  }

  if (cgdatptr->invert_hsync != 0)
  {
    tmp |= CLCDC_LCDTIMING2_IHS;
  }

  if (cgdatptr->invert_vsync != 0)
  {
    tmp |= CLCDC_LCDTIMING2_IVS;
  }

  // Compute clocks per line based on panel type
  switch (cgdatptr->lcd_panel_type)
  {
    case MONO_4BIT:
      // Clocks per line is a quarter of pixels per line
      tmp = tmp | CLCDC_LCDTIMING2_CPL((cgdatptr->pixels_per_line / 4) - 1);
      break;

    case MONO_8BIT:
      // Clocks per line is an eighth of pixels per line
      tmp = tmp | CLCDC_LCDTIMING2_CPL((cgdatptr->pixels_per_line / 8) - 1);
      break;

    case CSTN:
      // CSTN Clocks per line (* 3 / 8)
      tmp = tmp | CLCDC_LCDTIMING2_CPL(((cgdatptr->pixels_per_line * 3) / 8) - 1);
      break;

    case TFT:
    case ADTFT:
    case HRTFT:
    default:
      // Clocks per line and pixels per line are the same
      tmp = tmp | CLCDC_LCDTIMING2_CPL(cgdatptr->pixels_per_line - 1);
      break;
  }

  // Bypass pixel clock divider
  //tmp = tmp | CLCDC_LCDTIMING2_PCD_LO(8);
  //tmp = tmp | CLCDC_LCDTIMING2_PCD_LO(4);

//=========================================================TIMING==========================
  //tmp = tmp | CLCDC_LCDTIMING2_PCD_LO(2); //-> tak by�o
  //tmp = tmp | CLCDC_LCDTIMING2_PCD_LO(2); //- bez drgan 4
  //tmp = tmp | CLCDC_LCDTIMING2_PCD_LO(4); //- bez drgan 4
  if(TypPCB==PCBGET035)
	  tmp = tmp | CLCDC_LCDTIMING2_PCD_LO(8);
  else
	  tmp = tmp | CLCDC_LCDTIMING2_PCD_LO(2);

  lcdptr->lcdtiming2 = tmp;
  //=========================================================TIMING==========================

  // Skip line end control word - just set to 0x0
  lcdptr->lcdtiming3 = 0x00000000;

  // Default with all interrupts of
  lcdptr->lcdimsc = 0x00000000;

  // Default configuration is 16 bits per pixel with blue and blue not swapped
  tmp = CLCDC_LCDCTRL_BPP16;

  // blue and blue swapped rem
  //tmp |= CLCDC_LCDCTRL_BGR;

  switch (cgdatptr->lcd_panel_type)
  {
    case ADTFT:
    case HRTFT:
    case TFT:
      tmp |= CLCDC_LCDCTRL_TFT;
      break;

    case MONO_4BIT:
      tmp |= CLCDC_LCDCTRL_BW_MONO;
      break;

    case MONO_8BIT:
     // tmp |= (CLCDC_LCDCTRL_MON8 | CLCDC_LCDCTRL_BW_MONO);
      break;

    case CSTN:
	  ;
      break;

    default:
      // Unsupported panel type
      status = 1;
      break;
  }

  // Dual panel operation
  if (cgdatptr->dual_panel == 1)
  {
    tmp |= CLCDC_LCDCTRL_DUAL;
  }

  lcdptr->lcdctrl = tmp;

  //clear the palette (color is black )
  for (i = 0; i < sizeof(lcdptr->lcdpalette)/sizeof(lcdptr->lcdpalette[0]); i++)
  {
    lcdptr->lcdpalette[i] = 0;
  }

  LCD_CFG = 0x0;
  //LCD_CFG = 0x1;
  return 0;
}
#endif

/***********************************************************************
 *
 * Function: lcd_initialize
 *
 * Purpose: Initialize the LCD controller
 *
 * Processing:
 *     Prior to resetting LCD values, disable the LCD controller.
 *     Configurate the LCD registers with the values in the passed
 *     LCD_PARAM_T structure.
 *
 * Parameters:
 *     lcdcfgptr : A pointer to an LCD configuration data structure
 *
 * Outputs: None
 *
 * Returns: (0) if the LCD was initialized, otherwise (-1)
 *
 **********************************************************************/
uint8_t lcd_initialize(CLCDC_CFG_T *lcdcfgptr)
{
  uint32_t tmp, i;
  int32_t status = (int32_t)(0);
  LCD_PARAM_T *cgdatptr = lcdcfgptr->dptr;

  /* Disable the display in case it is on */
  LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_ENABLE;

  /* Generate the horizontal axis plane control word */
  tmp = (CLCDC_LCDTIMING0_PPL(cgdatptr->pixels_per_line) |
         CLCDC_LCDTIMING0_HSW(cgdatptr->h_sync_pulse_width) |
         CLCDC_LCDTIMING0_HFP(cgdatptr->h_front_porch) |
         CLCDC_LCDTIMING0_HBP(cgdatptr->h_back_porch));
  LPC_LCD->TIMH = tmp;

  /* Generate the vertical axis plane control word */
  tmp = (CLCDC_LCDTIMING1_LPP(cgdatptr->lines_per_panel) |
         CLCDC_LCDTIMING1_VSW(cgdatptr->v_sync_pulse_width) |
         CLCDC_LCDTIMING1_VFP(cgdatptr->v_front_porch) |
         CLCDC_LCDTIMING1_VBP(cgdatptr->v_back_porch));
  LPC_LCD->TIMV = tmp;

  /* Generate the clock and signal polarity control word */
  if(cgdatptr->ac_bias_frequency != 0)
  {
    /* STN panel has AC bias value */
    tmp = CLCDC_LCDTIMING2_ACB(cgdatptr->ac_bias_frequency);
  }
  else
  {
    tmp = 0;
  }

  if (cgdatptr->invert_output_enable != 0)
  {
    tmp |= CLCDC_LCDTIMING2_IOE;
  }

  if (cgdatptr->invert_panel_clock != 0)
  {
    tmp |= CLCDC_LCDTIMING2_IPC;
  }

  if (cgdatptr->invert_hsync != 0)
  {
    tmp |= CLCDC_LCDTIMING2_IHS;
  }

  if (cgdatptr->invert_vsync != 0)
  {
    tmp |= CLCDC_LCDTIMING2_IVS;
  }

  /* Compute clocks per line based on panel type */
  switch (cgdatptr->lcd_panel_type)
  {
    case MONO_4BIT:
      /* Clocks per line is a quarter of pixels per line */
      tmp = tmp | CLCDC_LCDTIMING2_CPL((cgdatptr->pixels_per_line / 4) - 1);
      break;

    case MONO_8BIT:
      /* Clocks per line is an eighth of pixels per line */
      tmp = tmp | CLCDC_LCDTIMING2_CPL((cgdatptr->pixels_per_line / 8) - 1);
      break;

    case CSTN:
      /* CSTN Clocks per line (* 3 / 8) */
      tmp = tmp | CLCDC_LCDTIMING2_CPL(((cgdatptr->pixels_per_line * 3) / 8) - 1);
      break;

    case TFT:
    case ADTFT:
    case HRTFT:
    default:
      /* Clocks per line and pixels per line are the same */
      tmp = tmp | CLCDC_LCDTIMING2_CPL(cgdatptr->pixels_per_line - 1);
      break;
  }

  /* Bypass pixel clock divider */
//#if (LCD_TYPE == SHARP_LQ064) || (LCD_TYPE == TRULY_G240320LTSW)
  tmp = tmp | CLCDC_LCDTIMING2_PCD_LO(8);
//#else
//  tmp = tmp | CLCDC_LCDTIMING2_PCD_LO(18);
//  // Set hi part of pixel clock divider (bits 27..31)*/
//  tmp = tmp | 0x08000000UL;
//#endif
  LPC_LCD->POL = tmp;

  /* Skip line end control word - just set to 0x0 */
  LPC_LCD->LE = 0x00000000;

  /* Default with all interrupts of */
  LPC_LCD->INTMSK = 0x00000000;

  /* Default configuration is 16 bits per pixel with blue and blue not swapped */
  tmp = CLCDC_LCDCTRL_BPP16;
  //tmp = CLCDC_LCDCTRL_BPP8;
  //tmp = CLCDC_LCDCTRL_BPP4;

  /* blue and blue swapped */
//  tmp |= CLCDC_LCDCTRL_BGR;

  switch (cgdatptr->lcd_panel_type)
  {
    case ADTFT:
    case HRTFT:
    case TFT:
      tmp |= CLCDC_LCDCTRL_TFT;
      break;

    case MONO_4BIT:
      tmp |= CLCDC_LCDCTRL_BW_MONO;
      break;

    case MONO_8BIT:
      tmp |= (CLCDC_LCDCTRL_MON8 | CLCDC_LCDCTRL_BW_MONO);
      break;

    case CSTN:
	  ;
      break;

    default:
      /* Unsupported panel type */
      status = (int32_t)(-1);
      break;
  }

  /* Dual panel operation */
  if (cgdatptr->dual_panel == 1)
  {
    tmp |= CLCDC_LCDCTRL_DUAL;
  }

  LPC_LCD->CTRL = tmp;

  /* clear the palette (color is black )*/
  for (i = 0; i < sizeof(LPC_LCD->PAL)/sizeof(LPC_LCD->PAL[0]); i++)
  {
    LPC_LCD->PAL[i] = 0;
  }

  LPC_SC->LCD_CFG = 0x0;
//  #if (LCD_TYPE == TRULY_G240320LTSW)
//    lcd_hw_init_Truly();
//    lcd_display_init_Truly();
//  #endif

  return status;
}


#if 0
long lcd_ioctl(long devid, long cmd, long arg)
{
  CLCDC_REGS_T *lcd;
  unsigned int i;
  CLCDC_CFG_T *lcdcfgptr = (CLCDC_CFG_T *) devid;
  long status = 1;

  PALETTE_ENTRY_T pal_entry, *ptr_pal_entry;
  unsigned char *pal_ptr;
  unsigned int *crsr_ptr;

  if (lcdcfgptr->init == 1)
  {
    status = 0;
    lcd = lcdcfgptr->regptr;

		switch (cmd)
		{
			case LCD_SET_BUFFER:
				// Set LCD display frame buffer, arg = memory pointer for image to be displayed
				lcd->lcdupbase = (unsigned int)arg;
			break;

			case LCD_CRSR_SET_BUFFER:
				// Set LCD cursor image, arg = memory pointer for image to be displayed
				crsr_ptr = (unsigned int *)arg;
				for(i = 0; i < 256; i++)
				{
					lcd->cursorimage[i] = *(unsigned int *)crsr_ptr;
					crsr_ptr++;
				}
			break;

			case LCD_PWR_ON:
				// Turn on the LCD controller power,arg = 1, turn on, arg = 0, turn off
				if (arg == 1)
				{
					lcd->lcdctrl |= CLCDC_LCDCTRL_ENABLE;
					lcd->lcdctrl |= CLCDC_LCDCTRL_PWR;
				}
				else if (arg == 0)
				{
					lcd->lcdctrl &= ~CLCDC_LCDCTRL_PWR;
					lcd->lcdctrl &= ~CLCDC_LCDCTRL_ENABLE;
				}
				else
				{
					status = 1;
				}
			break;

			case LCD_ENABLE:
				// Enable the LCD controller, arg = 1, enable, arg = 0, disable
				if (arg == 1)
				{
					lcd->lcdctrl |= CLCDC_LCDCTRL_ENABLE;
					//lcd->lcdctrl |= (1<<8); //BGR
				}
				else if (arg == 0)
				{
					lcd->lcdctrl &= ~CLCDC_LCDCTRL_ENABLE;
				}
				else
				{
					status = 1;
				}
			break;

			case LCD_CRSR_ENABLE:
				// Enable the LCD cursor, arg = 1, enable, arg = 0, disable
				if (arg == 1)
				{
					lcd->clcdcrsrctrl |= 1;
				}
				else if (arg == 0)
				{
					lcd->clcdcrsrctrl &= ~1;
				}
				else
				{
					status = 1;
				}
			break;

			case LCD_CRSR_NUM:
				// Select the LCD cursor number, arg = 0, 64x64, arg = 0, 1, 2, 3, 32x32
				lcd->clcdcrsrctrl &= ~30;
				lcd->clcdcrsrctrl |= (unsigned int)arg << 3;
			break;

			case LCD_CRSR_SIZE:
				// Set the LCD cursor size, arg = 1, 64x64, arg = 0, 32x32
				if (arg == 1)
				{
					lcd->clcdcrsrconfig |= 1;
				}
				else if (arg == 0)
				{
					lcd->clcdcrsrconfig &= ~1;
				}
				else
				{
					status = 1;
				}
			break;

			case LCD_CRSR_SYNC:
				// Set the LCD cursor frame sync, arg = 1, sync, arg = 0, async
				if (arg == 1)
				{
					lcd->clcdcrsrconfig |= 2;
				}
				else if (arg == 0)
				{
					lcd->clcdcrsrconfig &= ~2;
				}
				else
				{
					status = 1;
				}
			break;

			case LCD_LOAD_PALETTE:
				// This function supports loading of the color palette from
				// the C file generated by the bmp2c utility. It expects the
				// palette to be passed as an array of 32-bit BGR entries having
				// the following format:
				// 7:3 - Blue
				// 2:0 - Not used
				// 15:11 - Green
				// 10:8 - Not used
				// 23:19 - Red
				// 18:16 - Not used
				// 31:24 - Not used
				// arg = pointer to input palette table address

				ptr_pal_entry = &pal_entry;
				pal_ptr = (unsigned char *) arg;

				// 256 entry in the palette table
				for(i = 0; i < 256/2; i++)
				{
					pal_entry.Bl = (*pal_ptr++) >> 3;  // blue first
					pal_entry.Gl = (*pal_ptr++) >> 3;  // get green
					pal_entry.Rl = (*pal_ptr++) >> 3;  // get red
					pal_ptr++;      // skip over the unused unsigned char

					// do the most significant halfword of the palette
					pal_entry.Bu = (*pal_ptr++) >> 3;  // blue first
					pal_entry.Gu = (*pal_ptr++) >> 3;  // get green
					pal_entry.Ru = (*pal_ptr++) >> 3;  // get red
					pal_ptr++;      // skip over the unused unsigned char
					lcd->lcdpalette[i] = *(unsigned int *)ptr_pal_entry;
				}
			break;

			case LCD_CRSR_LOAD_PALETTE0:
				// 7:0 - Red
				//15:8 - Green
				//23:16 - Blue
				//31:24 - Not used
				lcd->clcdcrsrpalette0 = (unsigned int)arg;
			break;

			case LCD_CRSR_LOAD_PALETTE1:
				// 7:0 - Red
				//15:8 - Green
				//23:16 - Blue
				//31:24 - Not used
				lcd->clcdcrsrpalette1 = (unsigned int)arg;
			break;

			case LCD_SET_BPP:
				// Set current display bits per pixel, arg = bits per pixel
				switch (arg)
				{
					case BPP_IS_1:
					lcd->lcdctrl &= ~_SBF(1, _BITMASK(3));
					lcd->lcdctrl |= CLCDC_LCDCTRL_BPP1;
					break;

					case BPP_IS_2:
					lcd->lcdctrl &= ~_SBF(1, _BITMASK(3));
					lcd->lcdctrl |= CLCDC_LCDCTRL_BPP2;
					break;

					case BPP_IS_4:
					lcd->lcdctrl &= ~_SBF(1, _BITMASK(3));
					lcd->lcdctrl |= CLCDC_LCDCTRL_BPP4;
					break;

					case BPP_IS_8:
					lcd->lcdctrl &= ~_SBF(1, _BITMASK(3));
					lcd->lcdctrl |= CLCDC_LCDCTRL_BPP8;
					break;

					case BPP_IS_16:
					lcd->lcdctrl &= ~_SBF(1, _BITMASK(3));
					lcd->lcdctrl |= CLCDC_LCDCTRL_BPP16;
					break;

					case BPP_IS_24:
					lcd->lcdctrl &= ~_SBF(1, _BITMASK(3));
					lcd->lcdctrl |= CLCDC_LCDCTRL_BPP24;
					break;

					case BPP_IS_16_565_MODE:
					lcd->lcdctrl &= ~_SBF(1, _BITMASK(3));
					lcd->lcdctrl |= CLCDC_LCDCTRL_BPP16_565_MODE;
					break;

					case BPP_IS_12_444_MODE:
					lcd->lcdctrl &= ~_SBF(1, _BITMASK(3));
					lcd->lcdctrl |= CLCDC_LCDCTRL_BPP12_444_MODE;
					break;

					default:
					status = 1;
					break;
				}
			break;

			case LCD_SET_BGR:
				// LCD invert the bgr bit in the LCD controller. arg = 1, invert BGR for reverse color, arg = 0, BGR for normal color
				if (arg == 1)
				{
				 // Palette and direct color storage is
				 // blue in bits 4-0,
				 // green in bits 9-5,
				 // red in bits 14-10,
				 // intensity in bit 15.
				lcd->lcdctrl |= CLCDC_LCDCTRL_BGR;
				}
				else if (arg == 0)
				{
					//  Palette and direct color storage is
					//  red in bits 4-0,
					//  green in bits 9-5,
					//   blue in bits 14-10,
					//   intensity in bit 15.
					lcd->lcdctrl &= ~CLCDC_LCDCTRL_BGR;
				}
				else
				{
					status = 1;
				}
			break;

			case LCD_SET_INTERRUPT:
				// Set interrupt mask set/clear register
				if (arg == CLCDC_LCD_INTERRUPT_FUF)
				{
					lcd->lcdimsc |= CLCDC_LCD_INTERRUPT_FUF;
				}
				else if (arg == CLCDC_LCD_INTERRUPT_LNBU)
				{
					lcd->lcdimsc |= CLCDC_LCD_INTERRUPT_LNBU;
				}
				else if (arg == CLCDC_LCD_INTERRUPT_VCOMP)
				{
					lcd->lcdimsc |= CLCDC_LCD_INTERRUPT_VCOMP;
				}
				else if (arg == CLCDC_LCD_INTERRUPT_MBERROR)
				{
					lcd->lcdimsc |= CLCDC_LCD_INTERRUPT_MBERROR;
				}
				else
				{
					status = 1;
				}
			break;

			case LCD_CLR_INTERRUPT:
				// Set interrupt clear register
				if (arg == CLCDC_LCD_INTERRUPT_FUF)
				{
					lcd->lcdicr |= CLCDC_LCD_INTERRUPT_FUF;
				}
				else if (arg == CLCDC_LCD_INTERRUPT_LNBU)
				{
					lcd->lcdicr |= CLCDC_LCD_INTERRUPT_LNBU;
				}
				else if (arg == CLCDC_LCD_INTERRUPT_VCOMP)
				{
					lcd->lcdicr |= CLCDC_LCD_INTERRUPT_VCOMP;
				}
				else if (arg == CLCDC_LCD_INTERRUPT_MBERROR)
				{
					lcd->lcdicr |= CLCDC_LCD_INTERRUPT_MBERROR;
				}
				else
				{
					status = 1;
				}
			break;

			case LCD_CRSR_SET_INTERRUPT:
				// Set cursor interrupt mask set/clear register
				lcd->lcdcrsrimsc |= 1;
			break;

			case LCD_CRSR_CLR_INTERRUPT:
				// Set cursor interrupt clear register
				lcd->lcdcrsricr |= 1;
			break;

			case LCD_CRSR_XY:
				// Set lcd cursor xy position register
				lcd->clcdcrsrxy = (unsigned int)arg;
			break;

			case LCD_CRSR_CLIP:
				// Set lcd cursor clip position register*/
				lcd->clcdcrsrclip = (unsigned int)arg;
			break;

			case LCD_GET_STATUS:
				switch (arg)
				{
					case LCD_GET_BUFFER:
						// Returns LCD fram buffer address
						status = (long)lcd->lcdupbase;
					break;

					case LCD_GET_BPP:
						// Returns current LCD panel bit per pixel
						i = (lcd->lcdctrl) & _SBF(1,_BITMASK(3) );
							switch (i)
							{
								case CLCDC_LCDCTRL_BPP1:
									status = BPP_IS_1;
								break;

								case CLCDC_LCDCTRL_BPP2:
									status = BPP_IS_2;
								break;

								case CLCDC_LCDCTRL_BPP4:
									status = BPP_IS_4;
								break;

								case CLCDC_LCDCTRL_BPP8:
									status = BPP_IS_8;
								break;

								case CLCDC_LCDCTRL_BPP16:
									status = BPP_IS_16;
								break;

								case CLCDC_LCDCTRL_BPP24:
									status = BPP_IS_24;
								break;

								case CLCDC_LCDCTRL_BPP16_565_MODE:
									status = BPP_IS_16_565_MODE;
								break;

								case CLCDC_LCDCTRL_BPP12_444_MODE:
									status = BPP_IS_12_444_MODE;
								break;

								default:
									status = 1;
								break;
							}
					break;

					case LCD_GET_PALETTE:
						//Returns a pointer to palette table
						status = (long)lcd->lcdpalette;
					break;

					case LCD_CRSR_GET_PALETTE0:
						// Returns a pointer to cursor palette table
						status = (long)lcd->clcdcrsrpalette0;
					break;

					case LCD_CRSR_GET_PALETTE1:
						// Returns a pointer to cursor palette table
						status = (long)lcd->clcdcrsrpalette1;
					break;

					case LCD_GET_INTERRUPT:
						// Get interrupt mask sstatus register
						status = (long)lcd->lcdmis;
					break;

					case LCD_CRSR_GET_INTERRUPT:
						// Get cursor interrupt mask sstatus register
						status = (long)lcd->lcdcrsrmis;
					break;

					default:
						// Unsupported parameter
						status = 1;
					break;
				}
				break;

				case LCD_DMA_ON_4MT:
					// Set DMA requests to start when 4 or 8 entries are free in the CLCDC FIFOs, use arg = 1 for 4 entries, use arg = 0 for 8 entries
					if (arg == 0)
					{
						lcd->lcdctrl |= (1<<16); //DMA4
					}
					else if (arg == 1)
					{
						lcd->lcdctrl &= ~(1<<16);
					}
				break;


				default:
					// Unsupported parameter
					status = 1;
				break;
			}
	  }
  return status;
}
#endif

/***********************************************************************
 *
 * Function: lcd_ioctl
 *
 * Purpose: LCD configuration block
 *
 * Processing:
 *     This function is a large case block. Based on the passed function
 *     and option values, set or get the appropriate LCD
 *     parameter.
 *
 * Parameters:
 *     devid: Pointer to LCD config structure
 *     cmd:   ioctl command
 *     arg:   ioctl argument
 *
 * Outputs: None
 *
 * Returns: The status of the ioctl operation
 *
 **********************************************************************/
int32_t lcd_ioctl(int32_t devid,
               int32_t cmd,
               int32_t arg)
{
  uint32_t i;
  CLCDC_CFG_T *lcdcfgptr = (CLCDC_CFG_T *) devid;
  int32_t status = (int32_t)(-1);

  PALETTE_ENTRY_T pal_entry, *ptr_pal_entry;
  uint8_t *pal_ptr;
  uint32_t *crsr_ptr;

  if (lcdcfgptr->init == TRUE)
  {
    status = (int32_t)(0);

    switch (cmd)
    {
      case LCD_SET_BUFFER:
        /* Set LCD display frame buffer, arg = memory pointer for
           image to be displayed */
        LPC_LCD->UPBASE = (uint32_t)arg;
        break;

      case LCD_CRSR_SET_BUFFER:
        /* Set LCD cursor image, arg = memory pointer for
           image to be displayed */
        crsr_ptr = (uint32_t *)arg;
        for(i = 0; i < 256; i++)
        {
          LPC_LCD->CRSR_IMG[i] = *(uint32_t *)crsr_ptr;
          crsr_ptr++;
        }
        break;

      case LCD_PWR_ON:
        /* Turn on the LCD controller power,
           arg = 1, turn on, arg = 0, turn off */
        if (arg == 1)
        {
//	      LPC_GPIO0->SET = 0x18000000; /* P0.27, P0.28 output HIGH */
          LPC_LCD->CTRL |= CLCDC_LCDCTRL_ENABLE;
          LPC_LCD->CTRL |= CLCDC_LCDCTRL_PWR;
        }
        else if (arg == 0)
        {
          LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_PWR;
          LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_ENABLE;
//	      LPC_GPIO0->CLR = 0x18000000; /* P0.27, P0.28 output LOW */
        }
        else
        {
          status = (int32_t)(-1);
        }
        break;

      case LCD_ENABLE:
        /* Enable the LCD controller,
           arg = 1, enable, arg = 0, disable */
        if (arg == 1)
        {
          LPC_LCD->CTRL |= CLCDC_LCDCTRL_ENABLE;
        }
        else if (arg == 0)
        {
          LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_ENABLE;
        }
        else
        {
          status = (int32_t)(-1);
        }
        break;

      case LCD_CRSR_ENABLE:
        /* Enable the LCD cursor,
           arg = 1, enable, arg = 0, disable */
        if (arg == 1)
        {
          LPC_LCD->CRSR_CTRL |= 1;
        }
        else if (arg == 0)
        {
          LPC_LCD->CRSR_CTRL &= ~1;
        }
        else
        {
          status = (int32_t)(-1);
        }
        break;

      case LCD_CRSR_NUM:
        /* Select the LCD cursor number,
           arg = 0, 64x64, arg = 0, 1, 2, 3, 32x32 */
        LPC_LCD->CRSR_CTRL &= ~30;
        LPC_LCD->CRSR_CTRL |= (uint32_t)arg << 3;
        break;

      case LCD_CRSR_SIZE:
        /* Set the LCD cursor size,
           arg = 1, 64x64, arg = 0, 32x32 */
        if (arg == 1)
        {
          LPC_LCD->CRSR_CFG |= 1;
        }
        else if (arg == 0)
        {
          LPC_LCD->CRSR_CFG &= ~1;
        }
        else
        {
          status = (int32_t)(-1);
        }
        break;

      case LCD_CRSR_SYNC:
        /* Set the LCD cursor frame sync,
           arg = 1, sync, arg = 0, async */
        if (arg == 1)
        {
          LPC_LCD->CRSR_CFG |= 2;
        }
        else if (arg == 0)
        {
          LPC_LCD->CRSR_CFG &= ~2;
        }
        else
        {
          status = (int32_t)(-1);
        }
        break;

      case LCD_LOAD_PALETTE:
        /* This function supports loading of the color palette from
           the C file generated by the bmp2c utility. It expects the
           palette to be passed as an array of 32-bit BGR entries having
           the following format:
           7:3 - Blue
           2:0 - Not used
           15:11 - Green
           10:8 - Not used
           23:19 - Red
           18:16 - Not used
           31:24 - Not used
           arg = pointer to input palette table address */
        ptr_pal_entry = &pal_entry;
        pal_ptr = (uint8_t *) arg;

        /* 256 entry in the palette table */
        for(i = 0; i < 256/2; i++)
        {
          pal_entry.Bl = (*pal_ptr++) >> 3;  /* blue first */
          pal_entry.Gl = (*pal_ptr++) >> 3;  /* get green */
          pal_entry.Rl = (*pal_ptr++) >> 3;  /* get red */
          pal_ptr++;      /* skip over the unused byte */
          /* do the most significant halfword of the palette */
          pal_entry.Bu = (*pal_ptr++) >> 3;  /* blue first */
          pal_entry.Gu = (*pal_ptr++) >> 3;  /* get green */
          pal_entry.Ru = (*pal_ptr++) >> 3;  /* get red */
          pal_ptr++;      /* skip over the unused byte */

          LPC_LCD->PAL[i] = *(uint32_t *)ptr_pal_entry;
        }
        break;

      case LCD_CRSR_LOAD_PALETTE0:
        /* 7:0 - Red
           15:8 - Green
           23:16 - Blue
           31:24 - Not used*/
        LPC_LCD->CRSR_PAL0 = (uint32_t)arg;
        break;

      case LCD_CRSR_LOAD_PALETTE1:
        /* 7:0 - Red
           15:8 - Green
           23:16 - Blue
           31:24 - Not used*/
        LPC_LCD->CRSR_PAL1 = (uint32_t)arg;
        break;

      case LCD_SET_BPP:
        /* Set current display bits per pixel, arg = bits per pixel */
        switch (arg)
        {
          case BPP_IS_1:
            LPC_LCD->CTRL &= ~_SBF(1, _BITMASK(3));
            LPC_LCD->CTRL |= CLCDC_LCDCTRL_BPP1;
            break;

		  case BPP_IS_2:
            LPC_LCD->CTRL &= ~_SBF(1, _BITMASK(3));
            LPC_LCD->CTRL |= CLCDC_LCDCTRL_BPP2;
            break;

		  case BPP_IS_4:
            LPC_LCD->CTRL &= ~_SBF(1, _BITMASK(3));
            LPC_LCD->CTRL |= CLCDC_LCDCTRL_BPP4;
            break;

		  case BPP_IS_8:
            LPC_LCD->CTRL &= ~_SBF(1, _BITMASK(3));
            LPC_LCD->CTRL |= CLCDC_LCDCTRL_BPP8;
            break;

		  case BPP_IS_16:
            LPC_LCD->CTRL &= ~_SBF(1, _BITMASK(3));
            LPC_LCD->CTRL |= CLCDC_LCDCTRL_BPP16;
            break;

		  case BPP_IS_24:
            LPC_LCD->CTRL &= ~_SBF(1, _BITMASK(3));
            LPC_LCD->CTRL |= CLCDC_LCDCTRL_BPP24;
            break;

		  case BPP_IS_16_565_MODE:
            LPC_LCD->CTRL &= ~_SBF(1, _BITMASK(3));
            LPC_LCD->CTRL |= CLCDC_LCDCTRL_BPP16_565_MODE;
            break;

		  case BPP_IS_12_444_MODE:
            LPC_LCD->CTRL &= ~_SBF(1, _BITMASK(3));
            LPC_LCD->CTRL |= CLCDC_LCDCTRL_BPP12_444_MODE;
            break;

		  default:
            status = (int32_t)(-1);
            break;
        }
        break;

      case LCD_SET_BGR:
        /* LCD invert the bgr bit in the LCD controller. arg = 1, invert
           BGR for reverse color, arg = 0, BGR for normal color */
        if (arg == 1)
        {
          /*
           *   Palette and direct color storage is
           *   blue in bits 4-0,
           *   green in bits 9-5,
           *   red in bits 14-10,
           *   intensity in bit 15.
           */
          LPC_LCD->CTRL |= CLCDC_LCDCTRL_BGR;
        }
        else if (arg == 0)
        {
          /*
           *   Palette and direct color storage is
           *   red in bits 4-0,
           *   green in bits 9-5,
           *   blue in bits 14-10,
           *   intensity in bit 15.
           */
          LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_BGR;
        }
        else
        {
          status = (int32_t)(-1);
        }
        break;

      case LCD_SET_INTERRUPT:
        /* Set interrupt mask set/clear register */
        if (arg == CLCDC_LCD_INTERRUPT_FUF)
        {
          LPC_LCD->INTMSK |= CLCDC_LCD_INTERRUPT_FUF;
        }
        else if (arg == CLCDC_LCD_INTERRUPT_LNBU)
        {
          LPC_LCD->INTMSK |= CLCDC_LCD_INTERRUPT_LNBU;
        }
        else if (arg == CLCDC_LCD_INTERRUPT_VCOMP)
        {
          LPC_LCD->INTMSK |= CLCDC_LCD_INTERRUPT_VCOMP;
        }
        else if (arg == CLCDC_LCD_INTERRUPT_MBERROR)
        {
          LPC_LCD->INTMSK |= CLCDC_LCD_INTERRUPT_MBERROR;
        }
        else
        {
          status = (int32_t)(-1);
        }
        break;

      case LCD_CLR_INTERRUPT:
        /* Set interrupt clear register*/
        if (arg == CLCDC_LCD_INTERRUPT_FUF)
        {
          LPC_LCD->INTCLR = CLCDC_LCD_INTERRUPT_FUF;
        }
        else if (arg == CLCDC_LCD_INTERRUPT_LNBU)
        {
          LPC_LCD->INTCLR = CLCDC_LCD_INTERRUPT_LNBU;
        }
        else if (arg == CLCDC_LCD_INTERRUPT_VCOMP)
        {
          LPC_LCD->INTCLR = CLCDC_LCD_INTERRUPT_VCOMP;
        }
        else if (arg == CLCDC_LCD_INTERRUPT_MBERROR)
        {
          LPC_LCD->INTCLR = CLCDC_LCD_INTERRUPT_MBERROR;
        }
        else
        {
          status = (int32_t)(-1);
        }
        break;

      case LCD_CRSR_SET_INTERRUPT:
        /* Set cursor interrupt mask set/clear register */
        LPC_LCD->CRSR_INTMSK |= 1;
        break;

      case LCD_CRSR_CLR_INTERRUPT:
        /* Set cursor interrupt clear register*/
        LPC_LCD->CRSR_INTCLR = 1;
        break;

      case LCD_CRSR_XY:
        /* Set lcd cursor xy position register*/
        LPC_LCD->CRSR_XY = (uint32_t)arg;
        break;

      case LCD_CRSR_CLIP:
        /* Set lcd cursor clip position register*/
        LPC_LCD->CRSR_CLIP = (uint32_t)arg;
        break;

      case LCD_GET_STATUS:
        switch (arg)
        {
          case LCD_GET_BUFFER:
            /* Returns LCD fram buffer address */
            status = (int32_t)LPC_LCD->UPBASE;
            break;

          case LCD_GET_BPP:
            /* Returns current LCD panel bit per pixel */
            i = (LPC_LCD->CTRL) & _SBF(1,_BITMASK(3) );
            switch (i)
            {
              case CLCDC_LCDCTRL_BPP1:
                status = BPP_IS_1;
                break;

			  case CLCDC_LCDCTRL_BPP2:
                status = BPP_IS_2;
                break;

			  case CLCDC_LCDCTRL_BPP4:
                status = BPP_IS_4;
                break;

			  case CLCDC_LCDCTRL_BPP8:
                status = BPP_IS_8;
                break;

			  case CLCDC_LCDCTRL_BPP16:
                status = BPP_IS_16;
                break;

			  case CLCDC_LCDCTRL_BPP24:
                status = BPP_IS_24;
                break;

			  case CLCDC_LCDCTRL_BPP16_565_MODE:
                status = BPP_IS_16_565_MODE;
                break;

			  case CLCDC_LCDCTRL_BPP12_444_MODE:
                status = BPP_IS_12_444_MODE;
                break;

			  default:
                status = (int32_t)(-1);
                break;
            }
            break;

          case LCD_GET_PALETTE:
            /* Returns a pointer to palette table */
            status = (int32_t)LPC_LCD->PAL;
            break;

          case LCD_CRSR_GET_PALETTE0:
            /* Returns a pointer to cursor palette table */
            status = (int32_t)LPC_LCD->CRSR_PAL0;
            break;

          case LCD_CRSR_GET_PALETTE1:
            /* Returns a pointer to cursor palette table */
            status = (int32_t)LPC_LCD->CRSR_PAL1;
            break;

          case LCD_GET_INTERRUPT:
            /* Get interrupt mask sstatus register */
            status = (int32_t)LPC_LCD->INTSTAT;
            break;

          case LCD_CRSR_GET_INTERRUPT:
            /* Get cursor interrupt mask sstatus register */
            status = (int32_t)LPC_LCD->CRSR_INTSTAT;
            break;

          default:
            /* Unsupported parameter */
            status = (int32_t)(-1);
            break;
        }
        break;

      default:
        /* Unsupported parameter */
        status = (int32_t)(-1);
		break;
    }
  }
  return status;
}

